#ifndef AGT_SCENE_OBJECT_H
#define AGT_SCENE_OBJECT_H

namespace agtk {

struct StoreSceneObject
{
	StoreSceneObject (void) {
		name = "";
		path = "";
		materialName = "";
		materialPath = "";
		position.Set(0.0f,0.0f,0.0f);
		rotation.Set(0.0f,0.0f,0.0f);
		scale.Set(0.0f,0.0f,0.0f);
		overrideDefaultMaterial = false;
		visible = true;
		enabled = true;
		ghost = false;
		ignoreGravity = false;
		ignoreCollisions = false;
		sharedModel = true;
	}

	StoreSceneObject (FILE *t_fp) {
		// Read model info.
		name = ReadString(t_fp);
		path = ReadString(t_fp);
		fread(&sharedModel, sizeof(bool), 1, t_fp);

		// Write pos, rot, scale.
		fread(&position, sizeof(Vec3<float>), 1, t_fp);
		fread(&rotation, sizeof(Vec3<float>), 1, t_fp);
		fread(&scale, sizeof(Vec3<float>), 1, t_fp);

		// Write other data.
		fread(&visible, sizeof(bool), 1, t_fp);
		fread(&enabled, sizeof(bool), 1, t_fp);
		fread(&ghost, sizeof(bool), 1, t_fp);
		fread(&ignoreGravity, sizeof(bool), 1, t_fp);
		fread(&ignoreCollisions, sizeof(bool), 1, t_fp);

		// Write material information.
		fread(&overrideDefaultMaterial, sizeof(bool), 1, t_fp);
		if (overrideDefaultMaterial) {
			materialName = ReadString(t_fp);
			materialPath = ReadString(t_fp);
		}
	}

	bool WriteDataToFile(FILE *t_fp) {
		// Write model info.
		WriteString(name, t_fp);
		WriteString(path, t_fp);
		fwrite(&sharedModel, sizeof(bool), 1, t_fp);

		// Write pos, rot, scale.
		fwrite(&position, sizeof(Vec3<float>), 1, t_fp);
		fwrite(&rotation, sizeof(Vec3<float>), 1, t_fp);
		fwrite(&scale, sizeof(Vec3<float>), 1, t_fp);

		// Write other data.
		fwrite(&visible, sizeof(bool), 1, t_fp);
		fwrite(&enabled, sizeof(bool), 1, t_fp);
		fwrite(&ghost, sizeof(bool), 1, t_fp);
		fwrite(&ignoreGravity, sizeof(bool), 1, t_fp);
		fwrite(&ignoreCollisions, sizeof(bool), 1, t_fp);

		// Write material information.
		fwrite(&overrideDefaultMaterial, sizeof(bool), 1, t_fp);
		if (overrideDefaultMaterial) {
			WriteString(materialName, t_fp);
			WriteString(materialPath, t_fp);
		}

		return true;
	}

	std::string name;
	std::string path;
	std::string materialName;
	std::string materialPath;
	Vec3<float> position;
	Vec3<float> rotation;
	Vec3<float> scale;
	bool overrideDefaultMaterial; // Sould the loader look for additional material information?
	bool visible; // Indicates it the object is visible. Invisible objects are not rendered.
	bool enabled; // Indicates if the object is enabled. Disabled objects are not updated.
	bool ghost; // Indicates if the object is a ghost. Ghost objects cannot physically collide with anything.
	bool ignoreGravity; // Indicates if the maps's gravity vector should be added to m_velocity at update.
	bool ignoreCollisions; // Indicates if the object is to ignore collisions. Physical collisions can still occur, they're just not registered.
	bool sharedModel; // Indicates if the object is sharing the mesh or has exclusive access.
};

/** Class devining a static type scene object and it's properties.
	@author Tom Savage
**/
class SceneObject
{
public:
	SceneObject(char* name, char* path = "./", bool shared=true);
	SceneObject(StoreSceneObject t_store);
	~SceneObject(void);

	void Update(float gravity);
	void Render(void);

	void Drive( float force, bool lockYAxis = true );
	void Strafe( float force, bool lockYAxis = true );
	void Stop();

	void SetPosition( float x, float y, float z );
	void SetPosition( Vec3<float> position );
	void AddPosition( float x, float y, float z );
	void AddPosition( Vec3<float> position );
	Vec3<float> GetPosition();

	void SetRotation( float x, float y, float z );
	void SetRotation( Vec3<float> rotation );
	void AddRotation( float x, float y, float z );
	void AddRotation( Vec3<float> rotation );
	Vec3<float> GetRotation();

	void SetScale( float x, float y, float z );
	void SetScale( Vec3<float> scale );
	void AddScale( float x, float y, float z );
	void AddScale( Vec3<float> scale );
	Vec3<float> GetScale();

	void SetVelocity( float x, float y, float z );
	void SetVelocity( Vec3<float> velocity );
	void AddVelocity( float x, float y, float z );
	void AddVelocity( Vec3<float> velocity );
	Vec3<float> GetVelocity();

	void SetSpin( float x, float y, float z );
	void SetSpin( Vec3<float> spin );
	void AddSpin( float x, float y, float z );
	void AddSpin( Vec3<float> spin );
	Vec3<float> GetSpin();

	void SetForwardVector(float x, float y, float z);
	void SetForwardVector(Vec3<float> vector);
	void SetRightVector(float x, float y, float z);
	void SetRightVector(Vec3<float> vector);
	Vec3<float> GetForwardVector();
	Vec3<float> GetRightVector();

	void SetFriction( float friction );

	void SetVisible( bool visible );
	bool GetVisible();

	void SetEnabled( bool enabled );
	bool GetEnabled();

	void SetGhost( bool ghost );
	bool GetGhost();

	void SetIgnoreGravity( bool ignoreGravity );
	bool GetIgnoreGravity();

	void SetIgnoreCollisions( bool ignoreCollisions );
	bool GetIgnoreCollisions();

	void SetModel( char *name = NULL, char *path = "./", bool shared = true );
	Model* GetModel();

	void SetMaterial( Material* material);
	void SetDefaultMaterial();
	Material* GetMaterial();

	void GetIsOverriding();

	BoundingSphere *m_boundingSphere; // Bounding sphere.

	StoreSceneObject GetDataStore(void);

protected:
	Vec3<float> m_forward; // Object's forward vector.
	Vec3<float> m_right; // Object's right vector.

private:
	Vec3<float> m_position; // Object's position in 3D space.
	Vec3<float> m_rotation; // Object's rotation.
	Vec3<float> m_scale; // Object's scale.

	Vec3<float> m_velocity; // Object's velocity in units/second.
	Vec3<float> m_spin; // Object's spin in radians/second.

	char m_materialName[256]; // The objects current material's file name.
	char m_materialPath[256]; // The objects current material's file path.

	unsigned long m_type; // Identifies the scene object's parent class.
	float m_friction; // Friction applied to the object's velocity and spin.
	bool m_bOverridingDefaultMaterial; // Is the object overriding the model's default material?
	bool m_visible; // Indicates it the object is visible. Invisible objects are not rendered.
	bool m_enabled; // Indicates if the object is enabled. Disabled objects are not updated.
	bool m_ghost; // Indicates if the object is a ghost. Ghost objects cannot physically collide with anything.
	bool m_ignoreGravity; // Indicates if the maps's gravity vector should be added to m_velocity at update.
	bool m_ignoreCollisions; // Indicates if the object is to ignore collisions. Physical collisions can still occur, they're just not registered.
	bool m_sharedModel; // Indicates if the object is sharing the mesh or has exclusive access.
	Model *m_model; // Pointer to the object's mesh.
	Material *m_material; // Pointer to the current material.
};

}

#endif